package com.base.cn.platform.os.service.manage.count;

import com.base.cn.platform.os.common.j2cache.CustomCacheChannel;
import com.base.cn.platform.os.common.j2cache.J2CacheRegion;
import com.base.cn.platform.os.common.md5.MD5;
import com.base.cn.platform.os.common.mybatis.BaseBiz;
import com.base.cn.platform.os.common.utils.DateUtils;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.dao.manage.count.PageUVCountDao;
import com.base.cn.platform.os.entity.manage.count.PageUVCount;
import com.base.cn.platform.os.entity.manage.count.PageViewCount;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 页面UV统计Biz
 *
 * @author s.li
 * @create 2018-01-15-15:54
 */
@Service
public class PageUVCountBiz extends BaseBiz<PageUVCount,PageUVCountDao> {
    //操作100再更新数据库
    private static final int COUNT_DATA_LEN = 1000;
    //缓存KEY
    private static final String DATA_CACHE_KEY = "page_count_data_cache_key";
    @Autowired
    private PageViewCountBiz pageViewCountBiz;
    @Autowired
    private CustomCacheChannel customCacheChannel;

    /**
     * 添加页面统计
     * @param ip
     * @param pageKey
     * @param fromSource
     */
    @Async
    public synchronized void addPageCount(String ip,String pageKey,String fromSource){
        List<PageViewCount> pageViewCountList = (List<PageViewCount>)customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(),DATA_CACHE_KEY).getValue();
        if(ObjectUtils.isEmpty(pageViewCountList)){
            pageViewCountList = new ArrayList<>();
        }
        //创建访问对象
        PageViewCount pageViewCount = new PageViewCount();
        pageViewCount.setIpAddr(ip);
        pageViewCount.setPageKey(pageKey);
        pageViewCount.setFromSource(fromSource);
        pageViewCount.setCreateTime(new Date());
        pageViewCount.setUpdateTime(new Date());
        pageViewCountList.add(pageViewCount);
        //大于等于指定数阀值添加到数据库中
        if(pageViewCountList.size() >= COUNT_DATA_LEN){
            //添加PV
            pageViewCountBiz.addPageViewCount(pageViewCountList);
            //添加UV
            this.addPageUVCount(pageViewCountList);
            //移除缓存
            customCacheChannel.evict(J2CacheRegion.ONE_DAY_REGION.getKey(),DATA_CACHE_KEY);
            pageViewCountList = null;
        }
        if(ObjectUtils.isNotEmpty(pageViewCountList)){
            //重新更新缓存
            customCacheChannel.set(J2CacheRegion.ONE_DAY_REGION.getKey(),DATA_CACHE_KEY,pageViewCountList);
        }
    }

    /**
     * 添加碳UV统计数据
     * @param pageViewCountList
     */
    public void addPageUVCount(List<PageViewCount> pageViewCountList) {
        if(ObjectUtils.isNotEmpty(pageViewCountList)){
            List<PageUVCount> pageUVCountList = new ArrayList<>();
            pageViewCountList.forEach(e->{
                PageUVCount pageUVCount = new PageUVCount();
                pageUVCount.setPageKey(e.getPageKey());
                pageUVCount.setIpAddr(e.getIpAddr());
                pageUVCount.setFromSource(e.getFromSource());
                pageUVCount.setCreateTime(e.getCreateTime());
                pageUVCount.setUpdateTime(e.getUpdateTime());
                pageUVCountList.add(pageUVCount);
            });
            //去重UV数据
            List<PageUVCount> pageUVCounts = toRepeat(pageUVCountList);
            if(ObjectUtils.isNotEmpty(pageUVCounts)){
                String whereSql = " 1=1";
                //去重
                for(PageUVCount pageUVCount : pageUVCounts){
                    whereSql+=" or (pageKey='"+pageUVCount.getPageKey()+"' and ipAddr = '"+pageUVCount.getIpAddr()+"' and fromSource ='"+pageUVCount.getFromSource()+"' and DATE_FORMAT(createTime,'%y-%M-%d') = '"+DateUtils.format(pageUVCount.getCreateTime(),"yyy-MM-dd")+"')";
                }
                //查询是否有添加过
                List<PageUVCount> _pageUVCountList = this.find(whereSql,null,null);
                //去重两个List的数据
                List<PageUVCount> newList = toTwoRepeat(_pageUVCountList,pageUVCounts);
                if(ObjectUtils.isNotEmpty(newList)){
                    this.batchSave(newList);
                }
            }
        }
    }

    /**
     * 去掉两个List中的元素的重复
     * @param oldList 原数据库中的数据
     * @param newList 当前的数据
     * @return 返回去重复的List数据
     */
    private List<PageUVCount> toTwoRepeat(List<PageUVCount> oldList,List<PageUVCount> newList){
        if(ObjectUtils.isNotEmpty(oldList)){
            return newList;
        }
        if(ObjectUtils.isNotEmpty(newList)){
            Map<String,PageUVCount> oldMap = oldList.stream().collect(Collectors.toMap(e->getKey(e),e->e));
            List<PageUVCount> pageUVCountList = new ArrayList<>();
            newList.forEach(e->{
                String key = getKey(e);
                PageUVCount pageUVCount = oldMap.get(key);
                if(ObjectUtils.isEmpty(pageUVCount)){
                    pageUVCountList.add(e);
                }
            });
            return pageUVCountList;
        }
        return null;
    }

    /**
     * 去重复
     * @param pageUVCountList UV数据列表
     * @return 去重后的数据列表
     */
    private List<PageUVCount> toRepeat(List<PageUVCount> pageUVCountList){
        if(ObjectUtils.isNotEmpty(pageUVCountList)){
            Map<String,PageUVCount> pageUVCountMap = new HashMap<>();
            pageUVCountList.forEach(e->{
                String key = this.getKey(e);
                pageUVCountMap.put(key,e);
            });
            List<PageUVCount> pageUVCounts = new ArrayList<>();
            pageUVCountMap.forEach((k,v)->{
                pageUVCounts.add(v);
            });
            return pageUVCounts;
        }
        return null;
    }

    /**
     * 生成每个UV的KEY
     * @param pageUVCount
     * @return KEY
     */
    private String getKey(PageUVCount pageUVCount){
        String pageKey = pageUVCount.getPageKey();
        String ipAddr = pageUVCount.getIpAddr();
        String createTime = DateUtils.format(pageUVCount.getCreateTime(),"yyyy-MM-dd");
        String fromSource = pageUVCount.getFromSource();
        String key = MD5.getMD5(pageKey+ipAddr+createTime+fromSource);
        return key;
    }
}
